<template>
  <div class="vc-progress">
    <svg
      :style="{ transform: props.clockWise ? 'rotateY(0deg)' : 'rotateY(180deg)' }"
      xmlns="http://www.w3.org/2000/svg"
      width="100%"
      height="100%"
      :viewBox="`0 0 ${Number(props.width)} ${Number(props.width)}`"
    >
      <!-- 定义渐变色 -->
      <defs v-if="props?.gradients?.id">
        <linearGradient
          :id="props?.gradients?.id"
          :x1="props?.gradients?.x1"
          :y1="props?.gradients?.y1"
          :x2="props?.gradients?.x2"
          :y2="props?.gradients?.y2"
        >
          <stop
            v-for="(v, i) in props?.gradients?.colorStops"
            :key="i"
            :offset="v.offset"
            :stop-color="v.color"
          />
        </linearGradient>
      </defs>
      <defs v-else-if="props?.gradients?.length">
        <linearGradient
          v-for="item in props.gradients"
          :key="item.id"
          :id="item.id"
          :x1="item.x1"
          :y1="item.y1"
          :x2="item.x2"
          :y2="item.y2"
        >
          <stop
            v-for="(v, i) in item.colorStops"
            :key="i"
            :offset="v.offset"
            :stop-color="v.color"
          />
        </linearGradient>
      </defs>
      <defs v-else-if="bgColorArray || colorArray">
        <linearGradient v-if="bgColorArray" :id="getCircle()" x1="0" y1="0" x2="0" y2="100%">
          <stop offset="0%" :stop-color="bgColor[0]" />
          <stop offset="100%" :stop-color="bgColor[1]" />
        </linearGradient>
        <linearGradient v-if="colorArray" :id="getCircleItem()" x1="0" y1="0" x2="0" y2="100%">
          <stop offset="0%" :stop-color="color[0]" />
          <stop offset="100%" :stop-color="color[1]" />
        </linearGradient>
      </defs>
      <!-- 底部背景圆环 -->
      <circle
        :cx="props.width / 2"
        :cy="props.width / 2"
        :r="radius"
        :stroke="
          props?.gradients?.length
            ? `url(#${props?.gradients?.[0]?.id})`
            : bgColorArray
            ? `url(#${getCircle()})`
            : bgColor
        "
        :stroke-width="props.strokeWidth"
        fill="none"
      />
      <!-- 进度条圆环 -->
      <circle
        class="vc-progress-bar"
        :cx="props.width / 2"
        :cy="props.width / 2"
        :r="radius"
        :stroke-dasharray="strokeDasharray()"
        :stroke-dashoffset="strokeDashoffset()"
        :stroke="
          props?.gradients?.id
            ? `url(#${props?.gradients?.id})`
            : props?.gradients?.length
            ? `url(#${props?.gradients?.[1]?.id})`
            : colorArray
            ? `url(#${getCircleItem()})`
            : color
        "
        :stroke-width="props.strokeWidth"
        :stroke-linecap="props.strokeLinecap"
        fill="none"
        :transform="`rotate(-90, ${props.width / 2}, ${props.width / 2})`"
      >
        <animate
          v-if="animate"
          attributeName="stroke-dashoffset"
          attributeType="XML"
          :from="setValue('form')"
          :to="setValue('to')"
          :by="setValue('to')"
          :begin="props.begin"
          :dur="props.dur"
          :repeatCount="props.repeatCount"
          :fill="props.fill"
          v-bind="{ ...props.animateOptions }"
        ></animate>
      </circle>
      <!-- 环形分割细线 -->
      <circle
        :cx="props.width / 2"
        :cy="props.width / 2"
        :r="radius"
        :stroke="separateColor"
        fill="transparent"
        :stroke-width="props.strokeWidth + 2"
        :stroke-dasharray="separateDasharray()"
        :transform="`rotate(-90, ${props.width / 2}, ${props.width / 2})`"
      ></circle>
    </svg>
    <div class="vc-progress-text" v-if="props.showText">
      <slot name="text" :percent="percent"></slot>
    </div>
  </div>
</template>
<script>
  export default {
    name: 'Circle',
  };
</script>

<script setup>
  import {
    ref,
    watchEffect,
    watch,
    reactive,
    toRefs,
    defineProps,
    defineEmits,
    defineExpose,
    markRaw,
    computed,
    toRaw,
    onMounted,
  } from 'vue';
  import { isArray, isNumber } from '@/utils/config.js';
  import { setIndex, getIndex } from './setIndex.js';
  const props = defineProps({
    // 值
    value: {
      type: [String, Number],
      default: 0,
    },
    // 最大值
    maxValue: {
      type: [String, Number],
      default: 100,
    },
    // 画布宽度
    width: {
      type: Number,
      default: 100,
    },
    // 圆环宽度
    strokeWidth: {
      type: Number,
      default: 6,
    },
    // 是否是圆角
    strokeLinecap: {
      type: String,
      default: 'butt', // butt 方形  round  圆角
    },
    // 分割多少块
    part: {
      type: Number,
      default: 1, // 20
    },
    // 分割间距
    partGap: {
      type: Number,
      default: 0, // 5
    },
    // 分割线颜色
    separateColor: {
      type: String,
      default: '#fff',
    },
    // 背景色
    background: {
      type: [String, Array],
      default: '',
    },
    // 颜色
    color: {
      type: [String, Array],
      default: '',
    },
    // 显示文字
    showText: {
      type: Boolean,
      default: false,
    },
    // 顺时针方向
    clockWise: {
      type: Boolean,
      default: true,
    },
    // 自定义渐变色
    gradients: {
      type: [Object, Array],
      default: () => {},
    },
    animate: {
      type: Boolean,
      default: false,
    },
    from: {
      type: Number,
      default: undefined,
    },
    to: {
      type: Number,
      default: undefined,
    },
    by: {
      type: Number,
      default: undefined,
    },
    begin: {
      type: String,
      default: '0s',
    },
    dur: {
      type: String,
      default: '3s',
    },
    repeatCount: {
      type: String,
      default: '1',
    },
    fill: {
      type: String,
      default: 'freeze', //  动画结束停在终止状态 // remove  动画结束回到起始状态
    },
    animateOptions: {
      type: Object,
      default: () => {},
    },
  });
  const radius = computed(() => {
    return (props.width - props.strokeWidth) / 2;
  });
  const percent = ((Number(props.value) / Number(props.maxValue)) * 100).toFixed(2) / 1;
  const setValue = computed(() => {
    return (value) => {
      if (value === 'form') {
        return props.from ? Math.PI * radius.value * props.from : Math.PI * radius.value * 2;
      }
      if (value === 'to') {
        return props.to ? Math.PI * radius.value * props.to : strokeDashoffset();
      }
      if (value === 'by') {
        return props.by ? Math.PI * radius.value * props.by : undefined;
      }
    };
  });
  setIndex();
  const getCircle = () => {
    return 'circle' + getIndex();
  };
  const getCircleItem = () => {
    return 'circleItem' + getIndex();
  };
  const bgColorArray = ref(false);
  const colorArray = ref(false);
  const bgColor = ref(null);
  const color = ref(null);
  if (isArray(props.background)) {
    bgColor.value = props.background;
    bgColorArray.value = true;
  } else {
    bgColor.value = props.background || 'rgba(0,0,0,0.1)';
  }
  if (isArray(props.color)) {
    color.value = props.color;
    colorArray.value = true;
  } else {
    color.value = props.color || '#1890ff';
  }
  const strokeDasharray = () => {
    let value = 0;
    if (props.strokeLinecap === 'round') {
      value = 2 * Math.PI * radius.value + props.strokeWidth;
    } else {
      value = 2 * Math.PI * radius.value;
    }
    return value;
  };
  const separateDasharray = () => {
    let partLength = (2 * Math.PI * radius.value) / props.part;
    return `${props.partGap} ${partLength - props.partGap}`;
  };
  const strokeDashoffset = () => {
    let val = 0;
    let value = props.value / props.maxValue;
    if (value > 1) {
      value = 1;
    } else if (value < 0) {
      value = 0;
    }
    if (props.strokeLinecap === 'round') {
      val = 2 * Math.PI * radius.value * (1 - value) + props.strokeWidth;
    } else {
      val = 2 * Math.PI * radius.value * (1 - value);
    }
    return val;
  };
</script>

<style lang="less" scoped>
  .vc-progress {
    width: 100%;
    height: 100%;
    position: relative;
    &-bar {
      // transition: stroke-dashoffset 2s ease;
    }
    &-text {
      position: absolute;
      left: 50%;
      top: 50%;
      transform: translate(-50%, -50%);
      font-size: 20px;
      line-height: 1;
      text-align: center;
    }
  }
</style>
